package program_storage;

import java.util.Arrays;


public final class Token {

	/**
	 * Line and start column of the token
	 */
	private final int line, col;
	/**
	 * Type of the token
	 */
	private final TokenType type;
	/**
	 * Text of the token.
	 */
	private final String text;

	/**
	 * Returns true if this token is ok (it is not an error token).
	 *
	 * @return
	 */
	public boolean ok() {
		return type != TokenType.ERR;
	}

	/**
	 * Checks if the tokens type matches the given token type.
	 *
	 * @param type The token type to check for
	 * @return true, if the tokens type matches the given type.
	 */
	public boolean is(TokenType type) {
		return type.equals(this.type);
	}

	/**
	 * @param line
	 * @param col
	 * @param type
	 */
	public Token(int line, int col, TokenType type) {
		this(line, col, type, null);
	}

	/**
	 * @param line
	 * @param col
	 * @param type
	 * @param text
	 */
	public Token(int line, int col, TokenType type, String text) {
		this.line = line;
		this.col = col;
		this.type = type;
		this.text = text;
	}
	
	/**
	 * Create an artificial token.
	 * An artificial token is a token that did not occur in the program text.
	 * @param type The token type.
	 * @param text The text of the token.
	 * @return A token.
	 */
	public static Token createArtificial(TokenType type, String text) {
		return new Token(-1, -1, type, text);
	}
	
	/**
	 * Create an artificial token.
	 * An artificial token is a token that did not occur in the program text.
	 * @param type The token type.
	 * @return A token.
	 */
	public static Token createArtificial(TokenType type) {
		return createArtificial(type, null);
	}

	/**
	 * Returns the text of this token, its original character representation.
	 *
	 * @return the text of this token
	 */
	public String getText() {
		return text;
	}

	/**
	 * Returns the line of the token.
	 *
	 * @return the line of the token
	 */
	public int getLine() {
		return line;
	}

	/**
	 * Returns the column of the token.
	 *
	 * @return the column of the token
	 */
	public int getCol() {
		return col;
	}

	/**
	 * Returns the type of the token.
	 *
	 * @return the type of the token
	 */
	public TokenType getType() {
		return type;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see java.lang.Object#toString()
	 */
	public String toString() {
		return text != null ? text : type.toString();
	}

	/**
	 * Returns an error message for an unexpected type
	 *
	 * @param expected Set of expected types
	 * @return an error message for an unexpected type
	 */
	public String makeExpectOtherMsg(TokenType... expected) {
		String tmp = expected.length == 1 ? expected[0].toString() : "One of "
				+ Arrays.toString(expected);
		return String.format("At (%d, %d): %s expected but %s found", line,
				col, tmp, this);
	}

	/**
	 * Returns a prefix string for an error description
	 *
	 * @return a prefix string for an error description
	 */
	public String makeErrPrefix() {
		return String.format("At (%d, %d) %s: ", line, col, this);
	}

	/**
	 * Token that is used to represent an error.
	 */
	public static final Token ERROR = createArtificial(TokenType.ERR);

}
